package com.renu.jdependencyanalyser.asm;

import com.renu.jdependencyanalyser.core.ProjectInfo;
import com.renu.jdependencyanalyser.data.ProjectDataCenter;
import com.renu.jdependencyanalyser.model.ClassModel;
import com.renu.jdependencyanalyser.model.MethodModel;
import com.renu.jdependencyanalyser.utils.MyAsmUtil;
import com.renu.jdependencyanalyser.utils.MyFileUtil;
import com.renu.jdependencyanalyser.utils.MyProjectUtil;
import org.objectweb.asm.Label;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;

import java.util.Map;

public class CustomMethodVisitor extends MethodVisitor {

    private MethodModel methodModel;

    private ClassModel classModel;

    private ProjectInfo projectInfo = ProjectDataCenter.projectInfo;
    public CustomMethodVisitor(MethodModel methodModel) {
        super(Opcodes.ASM9);
        this.methodModel = methodModel;
        this.classModel = projectInfo.getClassModel(methodModel.getClassSig());
    }



    /**
     *
     * @param opcode
     * @param owner java/util/List
     * @param name  add
     * @param descriptor  (Ljava/lang/String;)V (I)V
     * @param isInterface
     */
    //当 ASM 访问到一个方法调用的指令时，会调用 visitMethodInsn 方法，从而允许你在这个时机执行自定义的逻辑。
    @Override
    public void visitMethodInsn(int opcode, String owner, String name, String descriptor, boolean isInterface) {
        // 处理方法调用
        //System.out.println("Method call: " + owner + ":" + name+":"+ descriptor);
        String classSig = MyFileUtil.convertPathToDot(owner);
        // jdk类库中的跳过
        if (MyProjectUtil.isJDKClassOrBasicType(classSig)){
            return;
        }
        ClassModel tgtClass = null;
        ClassModel srcClass = projectInfo.getClassModel(methodModel.getClassSig());
        String methodSig = MyAsmUtil.convertToSignature(classSig, name, descriptor);
        ClassModel ownClassModel = projectInfo.getClassModel(classSig);
        MethodModel tgtMethod = null;
        if (ownClassModel!= null){ //内部类
            tgtMethod =  projectInfo.getMethod(methodSig);
            if (tgtMethod == null){
                tgtMethod = new MethodModel(methodSig);
                projectInfo.addMethod(tgtMethod);
            }
            tgtClass = projectInfo.getClassModel(classSig);

        }else{
            tgtMethod =  projectInfo.getBorderMethod(methodSig);
            if (tgtMethod == null){
                tgtMethod = new MethodModel(methodSig);
                String clsSig = MyProjectUtil.getClsSigFromMthdSig(tgtMethod.getMethodSig());
                tgtMethod.setClassSig(classSig);
                projectInfo.addBorderMethod(tgtMethod);
                classModel.addOuterDpndCls(clsSig);
            }
            tgtClass = projectInfo.getOuterClassMap().get(classSig);
            projectInfo.addBorderClass(classSig);
        }
        projectInfo.bindSrcTgtCls(srcClass,tgtClass);
        projectInfo.bindInOut(this.methodModel,tgtMethod);
    }

    /**
     * 于访问局部变量表，其中包括方法的形参、局部变量以及可能的临时变量、方法的返回值
     * @param name
     * @param descriptor
     * @param signature
     * @param start
     * @param end
     * @param index
     */
    @Override
    public void visitLocalVariable(String name, String descriptor, String signature, Label start, Label end, int index) {
        String typeFromDescriptor = MyAsmUtil.getTypeFromDescriptor(descriptor);
        Map<String, ClassModel> outerClassMap = projectInfo.getOuterClassMap();
        if (outerClassMap.containsKey(typeFromDescriptor)){
            classModel.addOuterDpndCls(typeFromDescriptor);
        }

    }
}
